import { tauri } from '@tauri-apps/api';
import { appWindow } from '@tauri-apps/api/window';
import { IMessage, Message } from './message';
import { ref } from 'vue';
import { ByteView, CodecType, U16, U32, make } from './codec';
import { onNotify } from './notify';
import { pub } from './proto';

const NOTIFY_EVENT = 'notify-event';
const OTA_PROGRESS = 'OTA_PROGRESS';


const conn = {

    ota_prog: ref(0),

    async close() {
        await appWindow.close();
    },

    async avaliable_port_names() {
        return await tauri.invoke('avaliable_port_names') as string[];
    },

    async conn_is_open() {
        return await tauri.invoke('conn_is_open') as boolean;
    },

    async conn_open(name: string) {
        await tauri.invoke('conn_open', {
            name: name
        });
    },

    async conn_close() {
        await tauri.invoke('conn_close');
    },

    async conn_query(dst: number, cmd: number) {
        const msg = await tauri.invoke('conn_query', {
            dst: dst,
            cmd2: cmd,
        }) as IMessage;
        return new Message(msg);
    },

    async conn_request(dst: number, cmd: number, data: number[]) {
        const msg = await tauri.invoke('conn_request', {
            dst, data,
            cmd2: cmd,
        }) as IMessage;
        return new Message(msg);
    },

    async conn_ping(dst: number) {
        await tauri.invoke('conn_ping', {
            dst: dst,
        });
    },

    async conn_ota(dst: number, data: number[]) {
        await tauri.invoke('conn_ota', {
            dst: dst,
            data: data,
        });
    },

    async request(dst: number, cmd: number, ...ts: CodecType[]) {
        const buf = make(...ts);
        const msg = await this.conn_request(dst, cmd, buf);
        msg.assert();
        return msg;
    },

    async md5_sum(buf: number[]) {
        return await tauri.invoke('md5_sum', {
            buf: buf
        }) as number[];
    },

    async ota(dst: number, data: number[], cb: (prog: number) => void) {
        await this.request(
            dst, pub.OTA_START,
            new U32(data.length)
        );
        let id = 0;
        const FRAME_SIZE = 224;
        for (let index = 0; index < data.length; ) {
            let n = data.length - index;
            if (n > FRAME_SIZE) {
                n = FRAME_SIZE;
            }
            await this.request(
                dst, pub.OTA_TRANSLATE,
                new U16(id),
                new ByteView( data.slice(index, index + n) )
            );
            index += n;
            id += 1;
            cb( index * 100 / data.length );
        }
        const sum = await this.md5_sum(data);
        await this.request(
            dst, pub.OTA_COMPLETE,
            new ByteView(sum)
        );
    }
}

appWindow.listen<number>(OTA_PROGRESS, (env) => {
    let prog = env.payload; 
    conn.ota_prog.value = prog;
})

appWindow.listen<IMessage>(NOTIFY_EVENT, (env) => {
    onNotify( new Message(env.payload) );
})

export default conn;
